package fm

import (
	"context"
	"errors"
	logger "gitee.com/xluomo945/fm/log"
	"gitee.com/xluomo945/fm/setting"
	"github.com/gin-gonic/gin"
	"log"
	"net/http"
	"os"
	"os/signal"
	"time"
)

type AppConfig struct {
	// 注册路由
	RegisterRoute RegisterRouteHandle
	// 注册配置参数
	RegisterConfig RegisterConfigHandle
	// 启动前钩子
	RegisterBoot RegisterBootHandle
}

type Middleware struct {
	// 记录请求响应信息
	SaveDataFlow bool
	// 是否启用链路ID
	UseTrace bool
	// 跨域
	UseCors bool
	// JWT配置
	JwtConfig setting.JwtConfig
}

type App struct {
	// 服务运行配置
	AppConfig
	// 日志配置
	setting.LoggerConfig
	// 中间件配置
	Middleware
	// 项目配置文件
	setting.ConfigurationConfig
	// 内置文档日志服务
	setting.MiniServer
	// gin本体
	server *gin.Engine
	// 服务运行端口
	runServerPort string
	// 服务
	srv *http.Server
	// 基础配置
	config *config
	// 运行模式
	mode string
}

type RegisterBootHandle func() error

func (app *App) initialize() {
	// 加载配置
	if err := app.loadConfig(); err != nil {
		log.Fatal(err)
	}

	// 初始化日志
	if err := app.initLogger(); err != nil {
		log.Fatal(err)
	}

	// 连接数据库
	if err := app.openDatabase(); err != nil {
		log.Fatal(err)
	}

	// 设置路由
	if err := app.loadRouteGroup(); err != nil {
		log.Fatal(err)
	}

	// 创建服务
	app.srv = &http.Server{
		Addr:    app.runServerPort,
		Handler: app.server,
	}

	// 启动前
	if app.RegisterBoot != nil {
		if err := app.RegisterBoot(); err != nil {
			log.Fatal(err)
		}
	}
}

func (app *App) RunServer() {
	// 初始化服务
	app.initialize()
	defer app.cleanup()

	// 启动服务
	go app.run()

	// 等待结束信号
	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt)
	<-quit

	// 服务关机
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := app.srv.Shutdown(ctx); err != nil {
		log.Fatal("[FAIL] Server Shutdown:", err)
	}
	log.Println("[INFO] Server exiting")
}

func (app *App) run() {
	log.Printf("[INFO] server run and linsten to %s", app.runServerPort)
	if err := app.srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
		log.Fatalf("[FAIL] listen: %s\n", err)
	}
}

func (app *App) cleanup() {
	logger.Close()
}
